package org.convallaria.infrastruct.rg.service;

import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.convallaria.infrastruct.rg.config.RegistryProperties;
import org.convallaria.infrastruct.rg.exception.ServiceDiscoveryException;
import org.convallaria.infrastruct.rg.monitor.RegistryMetrics;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

import io.micrometer.core.instrument.Timer;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 服务发现管理器
 * 基于原生 Spring Cloud Nacos 的简化服务发现管理
 * 
 * @author gjh
 * @since 2025-01-27
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ServiceDiscoveryManager {
    
    private final NacosServiceDiscovery nacosServiceDiscovery;
    private final RegistryProperties registryProperties;
    private final RegistryMetrics registryMetrics;
    
    /**
     * 获取指定服务的所有实例
     * 
     * @param serviceId 服务ID
     * @return 服务实例列表
     */
    @Retryable(value = {Exception.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))
    public List<ServiceInstance> getInstances(String serviceId) {
        if (!registryProperties.getServiceDiscovery().isEnabled()) {
            log.warn("服务发现功能已禁用");
            return List.of();
        }
        
        Timer.Sample sample = registryMetrics.startServiceDiscoveryTimer();
        try {
            log.debug("获取服务实例: {}", serviceId);
            List<ServiceInstance> instances = nacosServiceDiscovery.getInstances(serviceId);
            
            // 更新监控指标
            registryMetrics.updateServiceInstanceCount(serviceId, instances.size());
            registryMetrics.recordServiceDiscoverySuccess(serviceId);
            
            return instances;
        } catch (Exception e) {
            String errorMsg = "获取服务实例失败: " + serviceId;
            log.error(errorMsg, e);
            registryMetrics.recordServiceDiscoveryFailure(serviceId, e.getMessage());
            throw new ServiceDiscoveryException(errorMsg, serviceId, e);
        } finally {
            registryMetrics.stopServiceDiscoveryTimer(sample, serviceId);
        }
    }
    
    /**
     * 获取指定服务的健康实例
     * 
     * @param serviceId 服务ID
     * @return 健康实例列表
     */
    public List<ServiceInstance> getHealthyInstances(String serviceId) {
        List<ServiceInstance> instances = getInstances(serviceId);
        return instances.stream()
                .filter(instance -> instance.getMetadata().getOrDefault("nacos.healthy", "true").equals("true"))
                .collect(Collectors.toList());
    }
    
    /**
     * 根据版本获取服务实例
     * 
     * @param serviceId 服务ID
     * @param version 版本号
     * @return 指定版本的实例列表
     */
    public List<ServiceInstance> getInstancesByVersion(String serviceId, String version) {
        List<ServiceInstance> instances = getInstances(serviceId);
        return instances.stream()
                .filter(instance -> version.equals(instance.getMetadata().get("version")))
                .collect(Collectors.toList());
    }
    
    /**
     * 根据区域获取服务实例
     * 
     * @param serviceId 服务ID
     * @param region 区域
     * @return 指定区域的实例列表
     */
    public List<ServiceInstance> getInstancesByRegion(String serviceId, String region) {
        List<ServiceInstance> instances = getInstances(serviceId);
        return instances.stream()
                .filter(instance -> region.equals(instance.getMetadata().get("region")))
                .collect(Collectors.toList());
    }
    
    /**
     * 根据标签获取服务实例
     * 
     * @param serviceId 服务ID
     * @param tags 标签
     * @return 指定标签的实例列表
     */
    public List<ServiceInstance> getInstancesByTags(String serviceId, String tags) {
        List<ServiceInstance> instances = getInstances(serviceId);
        return instances.stream()
                .filter(instance -> {
                    String instanceTags = instance.getMetadata().get("tags");
                    return instanceTags != null && instanceTags.contains(tags);
                })
                .collect(Collectors.toList());
    }
    
    /**
     * 获取服务实例的详细信息
     * 
     * @param serviceId 服务ID
     * @param instanceId 实例ID
     * @return 实例详细信息
     */
    public ServiceInstance getInstance(String serviceId, String instanceId) {
        List<ServiceInstance> instances = getInstances(serviceId);
        return instances.stream()
                .filter(instance -> instanceId.equals(instance.getInstanceId()))
                .findFirst()
                .orElse(null);
    }
    
    /**
     * 检查服务是否可用
     * 
     * @param serviceId 服务ID
     * @return 是否可用
     */
    public boolean isServiceAvailable(String serviceId) {
        List<ServiceInstance> instances = getHealthyInstances(serviceId);
        return !instances.isEmpty();
    }
    
    /**
     * 获取服务实例数量
     * 
     * @param serviceId 服务ID
     * @return 实例数量
     */
    public int getInstanceCount(String serviceId) {
        return getInstances(serviceId).size();
    }
    
    /**
     * 获取健康实例数量
     * 
     * @param serviceId 服务ID
     * @return 健康实例数量
     */
    public int getHealthyInstanceCount(String serviceId) {
        return getHealthyInstances(serviceId).size();
    }
    
    /**
     * 获取所有服务列表
     * 注意：此方法已简化，建议使用 Spring Cloud 原生的服务发现机制
     * 
     * @return 服务列表
     */
    public List<String> getServices() {
        // 由于 namingServiceInstance() 方法已弃用，建议使用 Spring Cloud 原生的服务发现
        log.warn("getServices() 方法已简化，建议使用 Spring Cloud 原生的 DiscoveryClient");
        return List.of();
    }
    
    /**
     * 订阅服务变化
     * 注意：此方法已简化，建议使用 Spring Cloud 原生的服务发现机制
     * 
     * @param serviceId 服务ID
     * @param callback 回调函数
     */
    public void subscribeService(String serviceId, ServiceChangeCallback callback) {
        // 由于 namingServiceInstance() 方法已弃用，建议使用 Spring Cloud 原生的服务发现
        log.warn("subscribeService() 方法已简化，建议使用 Spring Cloud 原生的服务发现机制");
    }
    
    /**
     * 服务变化回调接口
     */
    @FunctionalInterface
    public interface ServiceChangeCallback {
        void onServiceChange(String serviceId, List<ServiceInstance> instances);
    }
}
